﻿using BCC.Model.Enumeration;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;

namespace BCC.Common
{
    /// <summary>
    /// 工具类（新改动）
    /// </summary>
    public static class Utils
    {

        #region Json相关

        /// <summary>
        /// 序列化对象
        /// </summary>
        /// <param name="obj">内容</param>
        /// <returns></returns>
        public static string SerializeObject(object obj) => TryCatch(() => JsonConvert.SerializeObject(obj));

        /// <summary>
        /// 反序列化对象
        /// </summary>
        /// <param name="str">json字符串</param>
        /// <returns></returns>
        public static object DeserializeObject(string str) => TryCatch(() => JsonConvert.DeserializeObject(str));

        /// <summary>
        /// 反序列化对象（泛型）
        /// </summary>
        /// <param name="str">json字符串</param>
        /// <returns></returns>
        public static T DeserializeObject<T>(string str) => TryCatch(() => JsonConvert.DeserializeObject<T>(str));

        /// <summary>
        /// 将json字符串转为JObject对象
        /// </summary>
        /// <param name="str">json字符串</param>
        /// <returns></returns>
        public static JObject ToJObject(string str) => TryCatch(() => JObject.Parse(str));

        /// <summary>
        /// 将object类型转为对应的实体集合
        /// </summary>
        /// <typeparam name="T">返回值类型</typeparam>
        /// <param name="obj">参数</param>
        /// <returns></returns>
        public static T ObjectToList<T>(object obj) where T : class, new() => TryCatch(() => JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(obj), new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, MissingMemberHandling = MissingMemberHandling.Ignore }));

        #endregion

        #region Http相关

        /// <summary>
        /// Get请求
        /// </summary>
        /// <param name="url">请求地址</param>
        /// <param name="header">请求头，格式：name,value</param>
        /// <returns></returns>
        public static string Get(string url, string header = "")
        {
            return TryCatch(() =>
            {
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
                request.Method = "GET";
                request.ContentType = "text/html;charset=UTF-8";
                request.UserAgent = null;
                //request.Timeout = 6000;

                if (!string.IsNullOrEmpty(header))
                {
                    request.Headers.Add(header.Split(',')[0], header.Split(',')[1]);
                }

                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                Stream myResponseStream = response.GetResponseStream();
                StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("utf-8"));
                string retString = myStreamReader.ReadToEnd();
                myStreamReader.Close();
                myResponseStream.Close();

                return retString;
            });
        }

        /// <summary>
        /// Get请求（HttpClient方式）
        /// </summary>
        /// <param name="url">请求地址</param>
        /// <param name="dic">请求参数</param>
        /// <returns></returns>
        public static string Get(string url, Dictionary<string, string> dic)
        {
            return TryCatch(() =>
            {
                using (HttpClient httpClient = new HttpClient())
                {
                    string parameter = "?";

                    foreach (var item in dic)
                    {
                        parameter += string.Format("{0}={1}&", item.Key, item.Value);
                    }

                    parameter = parameter.TrimEnd('&');

                    if (dic.Count == 0)
                    {
                        parameter = parameter.TrimEnd('?');
                    }

                    httpClient.BaseAddress = new Uri(url);

                    return httpClient.GetAsync(parameter).Result.Content.ReadAsStringAsync().Result;
                }
            });
        }

        /// <summary>
        /// Post请求
        /// </summary>
        /// <param name="url">请求地址</param>
        /// <param name="data">请求数据</param>
        /// <returns></returns>
        public static string Post1(string url, string data, string header = "")
        {
            try
            {
                ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
                ServicePointManager.SecurityProtocol = (SecurityProtocolType)192 | (SecurityProtocolType)768 | (SecurityProtocolType)3072;

                //发送请求的数据
                HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(url);
                myHttpWebRequest.Method = "POST";
                UTF8Encoding encoding = new UTF8Encoding();
                byte[] byte1 = encoding.GetBytes(data);
                myHttpWebRequest.ContentType = "application/json";
                myHttpWebRequest.ContentLength = byte1.Length;

                //myHttpWebRequest.KeepAlive = false;
                //myHttpWebRequest.ProtocolVersion = HttpVersion.Version11;

                if (!string.IsNullOrEmpty(header))
                {
                    myHttpWebRequest.Headers.Add(header.Split(',')[0], header.Split(',')[1]);
                }

                Stream newStream = myHttpWebRequest.GetRequestStream();
                newStream.Write(byte1, 0, byte1.Length);
                newStream.Close();

                //发送成功后接收返回的XML信息
                HttpWebResponse response = (HttpWebResponse)myHttpWebRequest.GetResponse();
                string lcHtml = string.Empty;
                Encoding enc = Encoding.GetEncoding("UTF-8");
                Stream stream = response.GetResponseStream();
                StreamReader streamReader = new StreamReader(stream, enc);
                lcHtml = streamReader.ReadToEnd();
                return lcHtml;
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        public static string HttpPost(string url, object body, string Authorization)
        {

            //把用户传过来的数据转成“UTF-8”的字节流
            Encoding encoding = Encoding.UTF8;
            //先根据用户请求的uri构造请求地址
            //创建Web访问对象
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            request.Method = "POST";
            // request.Accept = "application/json";
            request.ContentType = "application/json; charset=UTF-8";
            request.Headers["Accept-Encoding"] = "gzip, deflate";
            if (Authorization != null)
            {
                request.Headers["Authorization"] = Authorization;
            }

            request.AutomaticDecompression = DecompressionMethods.GZip;

            var postBody = JsonConvert.SerializeObject(body);
            byte[] buffer = encoding.GetBytes(postBody);
            request.ContentLength = buffer.Length;
            request.GetRequestStream().Write(buffer, 0, buffer.Length);
            //通过Web访问对象获取响应内容
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            //通过响应内容流创建StreamReader对象，因为StreamReader更高级更快
            using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8))
            {
                return reader.ReadToEnd();//利用StreamReader就可以从响应内容从头读到尾
            }
        }

        public static string HttpGet(string url, string Authorization)
        {
            try
            {
                HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);    //创建一个请求示例 
                request.ContentType = "application/json";
                if (Authorization != null)
                {
                    request.Headers["Authorization"] = Authorization; //添加头
                }
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();  //获取响应，即发送请求
                using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8))
                {
                    return reader.ReadToEnd();//利用StreamReader就可以从响应内容从头读到尾
                }
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }

        /// <summary>
        /// Post请求
        /// </summary>
        /// <param name="url">请求地址</param>
        /// <param name="data">请求数据</param>
        /// <param name="header">请求头，格式：name,value</param>
        /// <returns></returns>
        public static string Post(string url, string data, string header = "", bool expect100Continue = true)
        {
            return TryCatch(() =>
            {
                //解决 请求被中止: 未能创建 SSL/TLS 安全通道。（.NET 4.0）
                //因为ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12  只有升级到.NET 4.5才可以用，
                //所以在.NET4. 0只要在抓取前面加 ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072 就可以啦
                ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;

                //发送请求的数据
                HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(url);
                myHttpWebRequest.Method = "POST";
                UTF8Encoding encoding = new UTF8Encoding();
                byte[] byte1 = encoding.GetBytes(data);
                myHttpWebRequest.ContentType = "application/json";
                myHttpWebRequest.ContentLength = byte1.Length;

                //在使⽤curl做POST的时候, 当要POST的数据⼤于1024字节的时候, curl并不会直接就发起POST请求, ⽽是会分为俩步,
                //发送⼀个请求, 包含⼀个Expect: 100 -continue, 询问Server使⽤愿意接受数据
                //接收到Server返回的100 - continue应答以后, 才把数据POST给Server
                //并不是所有的Server都会正确应答100 -continue, ⽐如lighttpd, 就会返回417 “Expectation Failed”, 则会造成逻辑出错

                //这个在Post的时候，一定要加上，如果服务器返回错误，他还会继续再去请求，不会使用之前的错误数据，做返回数据
                //Expect100Continue为true（默认是true），那么它发送的请求必须包含一个 Expect: 100 -continue 的头域，询问 Server 是否愿意接收数据；接收到 Server 返回的100-continue 应答以后，才把数据 POST 给Server；
                myHttpWebRequest.ServicePoint.Expect100Continue = expect100Continue;

                ////全局设置
                //ServicePointManager.Expect100Continue = false;

                if (!string.IsNullOrEmpty(header))
                {
                    myHttpWebRequest.Headers.Add(header.Split(',')[0], header.Split(',')[1]);
                }

                Stream newStream = myHttpWebRequest.GetRequestStream();
                newStream.Write(byte1, 0, byte1.Length);
                newStream.Close();

                //发送成功后接收返回的信息
                HttpWebResponse response = (HttpWebResponse)myHttpWebRequest.GetResponse();
                string lcHtml = string.Empty;
                Encoding enc = Encoding.GetEncoding("UTF-8");
                Stream stream = response.GetResponseStream();
                StreamReader streamReader = new StreamReader(stream, enc);
                lcHtml = streamReader.ReadToEnd();
                return lcHtml;
            });
        }

        /// <summary>
        /// 指定Post地址使用Get 方式获取全部字符串
        /// </summary>
        /// <param name="url">请求后台地址</param>
        /// <returns></returns>
        public static string Post(string url, Dictionary<string, string> dic)
        {
            //解决 请求被中止: 未能创建 SSL/TLS 安全通道。（.NET 4.0）
            //因为ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12  只有升级到.NET 4.5才可以用，
            //所以在.NET4. 0只要在抓取前面加 ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072 就可以啦
            ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;

            string result = "";
            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
            req.Method = "POST";
            req.ContentType = "application/x-www-form-urlencoded";
            #region 添加Post 参数
            StringBuilder builder = new StringBuilder();
            int i = 0;
            foreach (var item in dic)
            {
                if (i > 0)
                    builder.Append("&");
                builder.AppendFormat("{0}={1}", item.Key, item.Value);
                i++;
            }
            byte[] data = Encoding.UTF8.GetBytes(builder.ToString());
            req.ContentLength = data.Length;
            using (Stream reqStream = req.GetRequestStream())
            {
                reqStream.Write(data, 0, data.Length);
                reqStream.Close();
            }
            #endregion
            HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
            Stream stream = resp.GetResponseStream();
            //获取响应内容
            using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
            {
                result = reader.ReadToEnd();
            }
            return result;
        }

        /// <summary>
        /// 将响应的数据转为byte数组
        /// </summary>
        /// <param name="url">请求地址</param>
        /// <returns></returns>
        public static byte[] UrlToBytes(string url)
        {
            return TryCatch(() =>
            {
                byte[] b;

                HttpWebRequest myReq = (HttpWebRequest)WebRequest.Create(url);

                WebResponse myResp = myReq.GetResponse();

                Stream stream = myResp.GetResponseStream();

                using (BinaryReader binaryReader = new BinaryReader(stream))
                {
                    b = binaryReader.ReadBytes(500000);

                    binaryReader.Close();
                }

                myResp.Close();

                return b;
            });
        }

        #endregion

        #region 其他

        /// <summary>
        /// Base64转Image并保存
        /// </summary>
        /// <param name="base64">图片的base64字符串</param>
        /// <param name="folderPath">保存的文件夹路径（保存到服务器上该路径需要有写入权限）</param>
        /// <param name="fullFileName">传出完整文件名称（带文件后缀）</param>
        public static void Base64ToImage(string base64, string folderPath, out string fullFileName)
        {
            try
            {
                //将base64头部信息替换
                base64 = base64.Replace("data:image/png;base64,", "").Replace("data:image/jgp;base64,", "").Replace("data:image/jpg;base64,", "").Replace("data:image/jpeg;base64,", "");

                byte[] bytes = Convert.FromBase64String(base64);

                using (MemoryStream memStream = new MemoryStream(bytes))
                {
                    using (Image mImage = Image.FromStream(memStream))
                    {
                        using (Bitmap bp = new Bitmap(mImage))
                        {
                            fullFileName = $"{DateTime.Now:yyyyMMddHHmmssfff}.jpg";

                            bp.Save($@"{folderPath}{fullFileName}", ImageFormat.Jpeg);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        /// <summary>
        /// 判断字符串是否是Base64字符串
        /// </summary>
        /// <param name="str">需要判断的字符串</param>
        /// <returns></returns>
        public static bool IsBase64String(string str)
        {
            str = str.Trim();

            return (str.Length % 4 == 0) && Regex.IsMatch(str, @"^[a-zA-Z0-9\+/]*={0,3}$", RegexOptions.None);
        }

        /// <summary>
        /// 将byte数组转为图片并保存
        /// </summary>
        /// <param name="bytes"></param>
        /// <param name="folderPath">文件夹路径</param>
        /// <param name="fullFileName">传出完整文件名称（带文件后缀）</param>
        /// <returns></returns>
        public static void BytesToImage(byte[] bytes, string folderPath, out string fullFileName)
        {
            if (!Directory.Exists(folderPath))
            {
                Directory.CreateDirectory(folderPath);
            }

            fullFileName = $"{DateTime.Now:yyyyMMddHHmmssfff}.jpg";

            string filePath = $"{folderPath}{fullFileName}";

            using (FileStream fileStream = new FileStream(filePath, FileMode.Create))
            {
                using (BinaryWriter binaryWriter = new BinaryWriter(fileStream))
                {
                    binaryWriter.Write(bytes);
                }
            }
        }

        /// <summary>
        /// 【秒级】获取时间（北京时间）
        /// </summary>
        /// <param name="timestamp">10位时间戳</param>
        /// <returns></returns>
        public static DateTime GetDateTimeSeconds(long timestamp)
        {
            long begtime = timestamp * 10000000;
            DateTime dt_1970 = new DateTime(1970, 1, 1, 8, 0, 0);
            long tricks_1970 = dt_1970.Ticks;//1970年1月1日刻度
            long time_tricks = tricks_1970 + begtime;//日志日期刻度
            DateTime dt = new DateTime(time_tricks);//转化为DateTime
            return dt;
        }

        /// <summary>
        /// SHA1加密
        /// </summary>
        /// <param name="inputString">输入字符串。</param>
        /// <returns>加密后的字符串。（40个字符）</returns>
        public static string SHA1Encrypt(string inputString)
        {
            SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider();

            byte[] encryptedBytes = sha1.ComputeHash(Encoding.ASCII.GetBytes(inputString));

            StringBuilder sb = new StringBuilder();

            for (int i = 0; i < encryptedBytes.Length; i++)
            {
                sb.AppendFormat("{0:x2}", encryptedBytes[i]);
            }

            return sb.ToString();
        }

        /// <summary>
        /// 通用异常捕获方法
        /// </summary>
        /// <typeparam name="T">泛型T</typeparam>
        /// <param name="func">方法</param>
        /// <returns></returns>
        public static T TryCatch<T>(Func<T> func)
        {
            try
            {
                return func();
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        public static string Decrypt(string decryptValue, string key, Encoding encoding)
        {
            byte[] keyArray = encoding.GetBytes(key);
            byte[] ivArray = encoding.GetBytes(key);

            byte[] dataArray;

            try
            {
                dataArray = Convert.FromBase64String(decryptValue);
            }
            catch
            {
                return null;
            }

            DESCryptoServiceProvider provider = new DESCryptoServiceProvider();

            MemoryStream memoryStream = new MemoryStream(dataArray);

            CryptoStream cryptoStream = new CryptoStream(memoryStream,
                                                            provider.CreateDecryptor(keyArray, ivArray),
                                                            CryptoStreamMode.Read);

            StreamReader streamReader = new StreamReader(cryptoStream);

            return streamReader.ReadToEnd();
        }
        public static string Encrypt(string encryptValue, string key, Encoding encoding)
        {
            byte[] keyArray = encoding.GetBytes(key);
            byte[] ivArray = encoding.GetBytes(key);

            DESCryptoServiceProvider provider = new DESCryptoServiceProvider();

            MemoryStream memoryStream = new MemoryStream();

            CryptoStream cryptoStream = new CryptoStream(memoryStream,
                                                            provider.CreateEncryptor(keyArray, ivArray),
                                                            CryptoStreamMode.Write);

            //cryptoStream.Write(Encoding.UTF8.GetBytes(encryptValue), 0, Encoding.UTF8.GetBytes(encryptValue).Length);
            //cryptoStream.Flush();
            StreamWriter streamWriter = new StreamWriter(cryptoStream);
            streamWriter.Write(encryptValue);
            streamWriter.Flush();
            cryptoStream.FlushFinalBlock();
            //streamWriter.Flush();
            return Convert.ToBase64String(memoryStream.GetBuffer(), 0, (int)memoryStream.Length);
        }

        public static Image BytesToImage(byte[] byteArray)
        {
            using (var ms = new MemoryStream(byteArray))
            {
                return Image.FromStream(ms);
            }
        }

        public static ImageFormat SaveImage(ImageType imageType)
        {
            ImageFormat format = ImageFormat.Png;
            switch (imageType)
            {
                case ImageType.Png:
                    format = ImageFormat.Png;
                    break;
                case ImageType.Jpg:
                    format = ImageFormat.Jpeg;
                    break;
                case ImageType.Gif:
                    format = ImageFormat.Gif;
                    break;
                case ImageType.Bmp:
                    format = ImageFormat.Bmp;
                    break;
                default:
                    break;
            }
            return format;
        }

        #endregion

        #region 文件

        /// <summary>
        /// 往路径写数据
        /// </summary>
        /// <param name="filePath"></param>
        /// <param name="data"></param>
        public static void WriteToFile(string filePath, string data)
        {
            // Open the file or create it if it doesn't exist
            using (StreamWriter writer = new StreamWriter(filePath, true))
            {
                // Write the data to the file
                writer.WriteLine(data);
            }
        }

        /// <summary>
        /// 往文件写聊天信息
        /// </summary>
        /// <param name="data"></param>
        public static void WriteChatToFile(string data)
        {
            var filePath= ConfigurationManager.AppSettings["chatInfoFilePath"].Trim();
            var fileName = ConfigurationManager.AppSettings["chatInfofileName"].Trim();
            var filePathName = filePath + fileName;
            for (int i = 0; i < 3; i++)
            {
                if (!Directory.Exists(filePath))
                {
                    var dir = Directory.CreateDirectory(filePath);
                    if (dir.Exists)
                    {
                        WriteToFile(filePathName, data);
                    }
                }
                else
                {
                    WriteToFile(filePathName, data);
                    return;
                }
            }
        }

        #endregion
    }
}
